home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / wpjv1n2.zip / WPJV1N2.TXT < prev   
Text File  |  1993-02-01  |  76KB  |  2,047 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.     WW     WW     WW      PPPPPPPP              JJ
  7.     WW     WW     WW      PP    PP              JJ
  8.      WW   WWWW   WW       PP    PP              JJ
  9.      WW  WW  WW  WW       PPPPPPPP              JJ
  10.      WW  WW  WW  WW       PP             JJ     JJ
  11.       WWWW    WWWW        PP              JJ   JJ
  12.        WW      WW         PP               JJJJJ
  13.  
  14. ----------------------------------------------------------------
  15. The Windows Programmer's Journal                       Volume 01
  16. Copyright 1993 by Peter J. Davis                       Number 02
  17. and Mike Wallace                                          Feb 93
  18. ----------------------------------------------------------------
  19. A monthly forum for novice-advanced programmers to share ideas and concepts
  20. about programming in the Windows (tm) environment.
  21.  
  22. You can get in touch with the editor via Internet or Bitnet at:
  23.  
  24. HJ647C at GWUVM.BITNET   or   HJ647C at GWUVM.GWU.EDU
  25.  
  26. CompuServe: 71141,2071
  27.  
  28. or you can send paper mail to:
  29.  
  30. Windows Programmer's Journal
  31. 9436 Mirror Pond Dr.
  32. Fairfax, Va. 22032
  33.  
  34. The two GWUVM IDs are Pete's and CompuServe is Mike's.
  35.  
  36. We can also be reached by phone at: (703) 503-3165.
  37.  
  38. Microsoft, MS-DOS,  Microsoft Windows, Windows NT,  Windows for Workgroups,
  39. Windows for Pen Computing,  Win32, and Win32S are registered  trademarks of
  40. Microsoft Corporation.
  41.  
  42. Turbo  Pascal  for Windows,  Turbo C++  for  Windows, and  Borland  C++ for
  43. Windows are registered trademarks of Borland International.
  44.  
  45. WordPerfect is a registered trademark of WordPerfect Corporation.
  46.  
  47. WPJ is available  from the WINSDK, WINADV and MSWIN32 forums on CompuServe,
  48. and the  IBMPC, WINDOWS and  BORLAND forums  on GEnie.   On Internet,  it's
  49. available on WSMR-SIMTEL20.ARMY.MIL and FTP.CICA.INDIANA.EDU.  We upload it
  50. by  the 1st  of each  month and  is usually  available by  the 3rd  or 4th,
  51. depending on when the sysops receive it.
  52.  
  53. The Windows Programmer's Journal takes no responsibility for the content of
  54. the text within this document. All  text is the property and responsibility
  55. of the individual  authors. The  Windows Programmer's Journal  is solely  a
  56. vehicle for  allowing articles to be collected  and distributed in a common
  57. and easy to share form. No part  of the Windows Programmer's Journal may be
  58. re-published or  duplicated in  part or whole,  except in the  complete and
  59. unmodified form  of the Windows  Programmer's Journal, without  the express
  60. written  permission of  each  individual author.  The Windows  Programmer's
  61. Journal  may not be sold for  profit without the express written permission
  62. of  the  Editor, Peter  J.  Davis,  and only  then  after  he has  obtained
  63. permission from the individual authors.
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.                     Table of Contents
  71.  
  72. Subject                                        Page Author(s)
  73. -----------------------------------------------------------------
  74. WPJ.INI .......................................  3  Pete Davis
  75.  
  76. Letters .......................................  5  Readers
  77.  
  78. Install Program Part II .......................  7  Pete Davis
  79.  
  80. Programming a Drag&Drop Server ................  9  Andreas Furrer
  81.  
  82. C++ Beginner's Column ......................... 12  Mike Wallace
  83.  
  84. Beginner's   Corner   (C)   .........................   14     Pete   Davis
  85.                                                     & Mike Wallace
  86.  
  87. Using LZExpand Library ........................ 18  Alex Fedorov
  88.  
  89. Implementing a Linked List - Revisited ........ 21  Mike Wallace
  90.  
  91. An Introductory Look at DLLs and Make Files ... 22  Rod Haxton
  92.  
  93. The Windows Help Magician ..................... 29  Jim Youngman
  94.  
  95. Last Page ....................................  30  Mike Wallace
  96.  
  97. Getting in Touch with Us .....................  31  Pete & Mike
  98.  
  99.  
  100.  
  101.  
  102. Windows Programmer's Journal Staff:
  103.  
  104. Publishers ......................... Pete Davis and Mike Wallace
  105. Editor-in-Chief .................... Pete Davis
  106. Managing Editor .................... Mike Wallace
  107. Contributing Writer ................ Andreas Furrer
  108. Contributing Writer ................ Alex Federov
  109. Contributing Writer ................ Rod Haxton
  110. Contributing Writer ................ Jim Youngman
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.                                   WPJ.INI
  137.                                By Pete Davis
  138.  
  139.      Well, welcome to the second issue of the Windows Programmer's Journal.
  140. I  don't really know  what to  say. We've  been totally  blown away  by the
  141. response  we've been getting.  I'm writing this  on January 15th  and as of
  142. today, on Compuserve and  GEnie (the only two places we  can really see how
  143. many  issues are being downloaded) we've counted 873 downloads. That number
  144. goes up  every day and it doesn't include all  of the other places that the
  145. Windows  Programmer's Journal is available. We've gotten letters from a lot
  146. of you  with good and  bad things to  say. (When I  say bad, I  really mean
  147. critical.) Criticism is fine and  we're even going to publish some of it in
  148. this issue.
  149.  
  150.      We've also  received a terrific  response from Andrew  Schulman, whose
  151. book  we reviewed in  the last issue.  We'll show an  excerpt from that and
  152. other letters in the letters column. 
  153.  
  154.      One  of the criticisms  that was  most discussed  was the  Linked List
  155. article written  by Mike.  We  should be  receiving an  article from  Peter
  156. Shroesbree for  the next issue, showing an alternate way of doing it. We'll
  157. also have a  third article, showing yet  another way of doing this  in next
  158. month's issue, done by Rod Haxton,  who's writing an article in this issue.
  159. Since this has  become a  bit of a  hot topic,  we're going to  do a  short
  160. article in next  month's issue  about the advantages  and disadvantages  of
  161. each of these methods.
  162.  
  163.      We'd  also like to welcome David Campbell.   In March, he'll be taking
  164. over the beginner's  column. David has a good bit  of experience in Windows
  165. programming and is quite a hacker. He has shareware and commercial software
  166. on the market, so his experience will be valuable to all of us.
  167.  
  168.      Speaking of experience, I suppose it's time to kind of spill the beans
  169. about Mike and I.  So as not to confuse  anyone, neither Mike nor I  have a
  170. lot  of experience  programming  Windows. We  are  not authorities  on  the
  171. subject, but we don't think  that means we don't know a few  things that we
  172. can share. We're both learning a lot all the time. The linked list  article
  173. is an  example. All I'm  trying to say  is, don't  say, "Well, the  Windows
  174. Programmer's Journal says this, so it must  be true."  Not that you  would,
  175. but we all  can make mistakes and we're  not always going to be  right. The
  176. good thing is that there are obviously  a lot of you out there reading this
  177. and with your help, we can make corrections.
  178.  
  179.      We have another  article from Andreas Furrer this month. Last month he
  180. wrote  an article about  programming a Drag  & Drop client  in Windows 3.1.
  181. This month he's going  to talk about writing a Drag  & Drop server program.
  182. We've also  got an article by Alex  Federov of Moscow, Russia  on using the
  183. LZEXPAND.DLL. 
  184.  
  185.      Just got my  sample issue of Windows Tech Journal.  Ahem... How do you
  186. spell cancel? Nah, it ain't  that bad, just not really my type of magazine,
  187. I guess. Had an offer for Windows NT Developer.  12 issues for a mere $129.
  188. No thanks, I'll buy the book.
  189.  
  190.      Sorry, I digress. Geez, let's see, I'm going to be  writing the second
  191. part to the install program. I'm basically covering a lot of the stuff Alex
  192. Federov is covering.  His sample, however, is  written in Turbo Pascal  for
  193. Windows.  I was supposed to do an article on printing, this month, but I've
  194. been really busy, so I'm going to have to put it off until the  next issue.
  195. I'll share  a really  wonderful  experience with  you  about my  trials  in
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202. learning to print also.
  203.  
  204.      Ah, and  I almost forgot. We're going to do  a reader poll next month.
  205. Here's the question. What  format would you like  to see WPJ in? We've  had
  206. suggestions for a lot of different  formats. Mike is leaning in the Windows
  207. Write direction. That's ok,  but it doesn't quite have the power  of a real
  208. word processor, which is a pain when putting the whole thing together. Dave
  209. Campbell suggested Windows WINHELP format.  I've seen a sample, and I  have
  210. to  say,  it's  pretty damn  impressive.  We've  also  had suggestions  for
  211. Postscript and TeX. Now, the problem with Postscript,  as I see it, is it's
  212. BIG. That means it'll take longer for you to download. If you're getting it
  213. off Compuserve or  GEnie, or some other pay system, it costs you. As far as
  214. TeX, I  don't know how  popular it  is. Personally I've  never used it  and
  215. don't know  anyone who  has (though  I've heard good  things about  it), so
  216. unless we get a huge outcry for the TeX format, I don't think we'll go that
  217. way. That leaves  the regular text  format that you're  getting it in  now,
  218. Write format, or  WinHelp format. Now, before you cast  your votes, we will
  219. be distributing the March issue in all three of those formats. After March,
  220. tell us what you think. I just wanted to give everyone a heads-up on that.
  221.  
  222.      One  final note: We mentioned our BBS in  the last issue. Well, we had
  223. it up for  about 3 days and  before anyone had a  chance to call, the  hard
  224. drive got wiped out. I've  been trying to get the thing  back together, but
  225. the hard drive is really  getting unreliable. What it looks like  I'm going
  226. to have to  do is get rid of it and replace it. I currently have two 65 meg
  227. Seagates  which have  done their  time.  The main  one (C:  drive) is  just
  228. getting a little too flakey,  so we're going to toss it and  probably throw
  229. in a 600 meg hard drive that we saw a good deal on. (We have two  machines,
  230. so we're  going to network  them so that  Mike can use  the 600 meg  on his
  231. machine too.)  Anyway, we don't know if we'll have  it up this month. If we
  232. don't, it'll be next month. Sorry for the problems there.
  233.  
  234.      I'd like to thank everyone who's  reading the magazine and sending  in
  235. their comments and suggestions. It helps us to do a better job and it helps
  236. you get a better magazine. We really appreciate your comments and we'd like
  237. you to  keep them coming.  Also, as  always, please, please,  send us  your
  238. articles. We want them!!!!
  239.  
  240.      By the way, it's now January 31  and the number of downloads on  GEnie
  241. and Compuserve alone are about 1200, total. Sorry, just about  broke my arm
  242. patting myself on the back there. 'Scuse me while I pump up our egos a bit.
  243. We'll try not to do that too often.
  244.  
  245.      And remember, if you read it  in the Programmer's Journal, it might be
  246. right!
  247.  
  248.                                                   _Pete Davis
  249.  
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.                                   Letters
  269.  
  270. Date:  04-Jan-93 13:48 EST
  271. From:  Andrew Schulman [76320,302]
  272. Subj:  Windows Programmer's Journal
  273.  
  274.      Thanks  very much  for sending the  magazine.   Of course,  I read the
  275. review of UndocWin  very carefully, and read the rest  pretty carefully.  I
  276. guess my main question  is, Why the heck are you guys doing this?  You both
  277. write well.  The material is interesting and  entertaining.  So why are you
  278. giving it away  for free?   Doesn't make  any sense  to me.   You could  be
  279. making  money from  your  writing, though  not  necessarily with  your  own
  280. magazine.   But clearly you  could write  for MSJ, WDDJ,  or Dr. Dobb's  (I
  281. won't mention that other magazine that covers Windows programming...).  So,
  282. like, why give the stuff away? 
  283.  
  284.      Thanks  for the kind review of UndocWin.   If you are looking for more
  285. stuff on  how Windows operates,  I think  you'll be pleased  with the  book
  286. "Windows Internals" that Matt Pietrek is just finishing up.  It will appear
  287. in the series  of books I am editing for  Addison-Wesley, probably in March
  288. or  April.   Most of the  book is  typeset already.   It  presents detailed
  289. pseudocode for many  of the key Windows API functions.  For example, if you
  290. want to know what CreateWindow or RegisterClass or GetMessage or ShowWindow
  291. or GlobalAlloc actually does, in sometimes painful detail, this is it.
  292.  
  293.      UndocNT?  Well, that's an interesting question.  Microsoft has   asked
  294. me that question too.   As you know, the  entire NT API (as opposed  to the
  295. Win32 API) is right  now undocumented.  Helen Custer's book "Inside Windows
  296. NT"  does a good job of showing in a conceptual-overview sort of way how NT
  297. works, but as she  herself says in  the preface the book's  goal is to  how
  298. "exactly how NT sort of  works"  Exactly sort  of!  A brief examination  of
  299. the NT process viewer,  PVIEW.EXE, shows that there is  some dynamite stuff
  300. at the NT API layer that currently  isn't available via Win32.  (Ray Duncan
  301. was  who  put me  on  to  looking  at PVIEW;  I  looked  at it  first  with
  302. Microsoft's COFF -DUMP,  and have  since been modifying  my Windows  Source
  303. product to disassemble PE files.) 
  304.  
  305.      So there's a  lot of interesting stuff in NT.   And Microsoft actually
  306. seems to look _favorably_ on an Undocumented NT book.  This way, they don't
  307. have to document it!
  308.  
  309.      There's just  one problem:  to do a book  like UndocDOS or UndocWin or
  310. UndocNT takes  a long time.   Basically, it's not  worth doing such  a book
  311. unless you're going to sell a  lot of copies.  And  I do not think that  NT
  312. anything is  going to sell  a lot of  copies for a few  years.  To  me, the
  313. whole thing is reminiscent  of OS/2 in a lot of ways.   (In a lots of ways,
  314. it's not  reminiscent of OS/2 of  course:  Microsoft has  clearly learned a
  315. lot of lessons, but I think it's also repeating some of the same mistakes.)
  316. Me, I'm putting my money on Win32s rather  than NT.  I told one of the guys
  317. at Microsoft  that I would  start working on  it after they  sold a million
  318. copies of NT.  I'm not holding my breath. 
  319.  
  320.      In looking over  this letter, I  realize that the phrases  "money" and
  321. "sell" keep appearing.  This must say something about me.  :-)
  322.  
  323. Regards,
  324. Andrew
  325.  
  326. [Thanks  for the  kind  review of  WPJ,  Andrew, and  the  tip on  "Windows
  327. Internals" - I look forward to reading it. -Mike]
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334. Date:  10-Jan-93 03:22 EST
  335. From:  Alex Fedorov [72400,274]
  336. Subj:  WPJ
  337.  
  338. Mike--
  339.  
  340.      Here is Alex Fedorov from Moscow,  Russia.  Yesterday I downloaded the
  341. 1st  issue of  WPJ. This is  great! I've  a whole  set of  Peter's previous
  342. magazine - Pascal News Letter. I liked it. I'm working as an editor for our
  343. "Computer Press" magazine - the most popular computer magazine here. Before
  344. that I've worked  as tech support person for Borland Pascal  for one of its
  345. distributors here.  Reading  WPJ.INI section,  I've realized  that you  are
  346. looking for authors. I would like to offer a set  of articles, dedicated to
  347. changes in  Windows 3.1 - new DLLs, concepts and APIs from Turbo Pascal for
  348. Windows.   These articles  were prepared for  publication here  and can  be
  349. translated in  a short time. The  articles cover new  kernel API functions,
  350. TrueType  fonts,  OLE/DDEML,  COMMDLG,  Drag  and  Drop,  VER and  TOOLHELP
  351. libraries.   Beside the  texts, there is  plenty of examples,  which can be
  352. used like small utilities.
  353.  
  354.      Please  let me know  if this is  interesting for beginner/intermediate
  355. section of WPJ. Also, I've plenty of hacks for advanced users. 
  356.  
  357.                                    Let me know if you need more
  358.                                    information.
  359.   
  360.                                    Sincerely, Alex
  361.  
  362. [Glad you liked the 1st issue, Alex.  Hope the rest go over as well.  We've
  363. included  your first  article in  this issue  and plan  to include  more in
  364. future issues. -Mike] 
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379.  
  380.  
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.                 Install Program Part II: File Decompression
  401.                                By Pete Davis
  402.  
  403.      Well, I don't know where my head's been, but I think I found  it. Last
  404. time  I  was  discussing  how  much   I  was  dreading  coming  up  with  a
  405. decompression  algorithm and it  occurred to me  that I don't  need to. The
  406. LZEXPAND.DLL has all the routines we need for decompression. I was still in
  407. the  Windows  3.0  mindset.  When  I  did  my  first  install  program  the
  408. LZEXPAND.DLL  wasn't available  to me, so  I didn't  even consider  it last
  409. month. Several of you mentioned this to me also. In retrospect, it seems so
  410. obvious. Oh well.... You should also  read Alex Fedorov's article on  using
  411. LZEXPAND under Turbo Pascal in this issue.
  412.  
  413.      Ok, so for those of you that don't know, LZEXPAND.DLL is a set of file
  414. decompression  routines  supplied  with  Windows 3.1.  Because  I  want  to
  415. maintain 3.0 compatibility (a bad  habit I pick up from work, I guess) I am
  416. supplying the LZEXPAND.DLL file with this issue.
  417.  
  418.      This article isn't going to be too long  because, thanks to Microsoft,
  419. the LZEXPAND.DLL takes all the work out of file decompression. They make it
  420. as easy as opening, reading, and closing a file. 
  421.  
  422.      One feature we're going to  have in our program is two  of those nifty
  423. little progress bars that shows us how far we are through our installation.
  424. One is going  to show progress  for the entire  installation. The other  is
  425. going to handle  progress for the current file. This is where we run into a
  426. bit  of a problem.  In the past  I used the  .ZIP format and  that kept the
  427. total uncompressed  file size  internally so  I could  figure out how  many
  428. bytes the file was going to be uncompressed at run-time. I have been unable
  429. to find a way  to do that with the LZEXPAND.DLL so we're going to have that
  430. in our SETUP.INF file.
  431.  
  432.      Let me run off on a little tangent here and explain the SETUP.INF. The
  433. SETUP.INF  is going  to be  the file  that makes  our installation  program
  434. generic. The SETUP.INF  file is going to keep information  like the name of
  435. the Application  group, the default destination  directory, whether certain
  436. files will go  into sub-directories within  the application directory,  how
  437. large each  file is un-compressed, what  the compressed filename  is on the
  438. installation  diskette and so on and  so on. We're also  going to break the
  439. rules a  bit. I mentioned earlier  the trouble that Mike got  into with his
  440. article about doing Global linked lists. Well, we're going to use his 'bad'
  441. example and in  this case, I  believe I can  justify it.  First of all,  an
  442. install  program has, in this programmer's mind,  every right to hog up the
  443. CPU.  (Just  try to  run  another  program while  the  floppy drive's  busy
  444. anyway.) Second, it's going to be  playing around with Program Manager, and
  445. when that's going  on, you don't want  the user clicking around  everywhere
  446. and  screwing up the installation, so, we're going  to hog up the CPU. That
  447. means that whatever  global memory is there is ours for the taking and gosh
  448. darnit, we're going  to take what  we want! So, bear  with me on  our nasty
  449. little global linked list. (That will be in next months issue).
  450.  
  451.      Well,  that little  side-track got  a little  longer than  I expected.
  452. Anyway, back to  LZEXPAND. So, we know the uncompressed  file size from our
  453. SETUP.INF.  What's left is to get our current progress. That's pretty easy.
  454. The way it works is that when you read  from a compressed file, you have to
  455. allocate the buffer. That means that if the buffer is, say, 20k, then every
  456. time  20k of data  is decompressed, we  have to write  out the data  in the
  457. buffer to our uncompressed file on the destination disk. So, all we have to
  458. do  is  update  our  progress  bar  by 20k  and  whatever  percent  of  the
  459. installation that is. The formulas are really simple. 
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.      The   commands  we're  going  to   be  concerned  about  are:  LZInit,
  467. GetExpandedName, LZRead, and LZClose. 
  468.  
  469.      The LZInit function essentially allocates memory for the decompression
  470. algorithm  and initializes some data that the algorithm uses. The prototype
  471. is:
  472.  
  473. HFILE LZInit(HFILE SrcFile)
  474.  
  475.      SrcFile is the file  handle received from a regular  OpenFile function
  476. call.  We use this handle  only for the  LZInit, but we keep  the file open
  477. until the end of our  decompression. If the return value from LZInit is the
  478. same  as SrcFile, then that means our  file isn't compressed. If the return
  479. value  is greater  than  0,  then it  is  a  special  file handle  for  our
  480. compressed file. If the return value is less than 0, then we have an error.
  481.  
  482.      After we  do the LZInit, we  have to do  a GetExpandedName to  get the
  483. filename of our file as  it was prior to  being compressed. We'll use  this
  484. filename when we open the output file to write the  uncompressed version of
  485. the file. The prototype for the GetExpandedName is:
  486.  
  487. int GetExpandedName(LPCSTR lpszSource, LPSTR lpszBuffer);
  488.  
  489.      lpszSource  is a pointer  to the string  that has the  filename of the
  490. compressed file.  lpszBuffer will have the  name of the file  prior to it's
  491. compression. This  is the filename that  we will use when  writing the file
  492. back. The return value is TRUE if successful.
  493.  
  494.      After that, of course, is the LZRead which, again (isn't this just the
  495. most bizarre thing) is a lot like the _lread function. It's prototype:
  496.  
  497. int LZRead(HFILE hf, void FAR* lpvBuf, int cb);
  498.  
  499.      hf  is the  file handle  we returned  from the  LZInit. lpvBuf  is our
  500. buffer to hold the  data we read. cb is  the number of bytes read  from the
  501. file.  This is the  number we'll use  to write the  data out to  our output
  502. file.
  503.  
  504.      Last, but not least, the LZClose. It's simply:
  505.  
  506. void LZClose(HFILE hf);
  507.  
  508.      where hf is the file handle to close. 
  509.  
  510.      That's  about all  we need.  It's pretty  simple. There  are other  LZ
  511. commands  and maybe  at some  point I'll  have a  discussion of  the entire
  512. library of  commands. At this  point, though, it's confession  time. I must
  513. admit I have no  code to go with this article this month. Fear not, it will
  514. be in next  months issue. I'm  hoping to wrap up  the entire thing  in next
  515. months issue,  and with  several other  people helping  out in next  months
  516. issue, that just  might be possible. Anyway, until then,  mer i beaucoup et
  517. au r voir. (Just trying to be a little international there.)
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.           Programming a Drag&Drop Server for Windows 3.1 with TPW
  533.                              by Andreas Furrer
  534.  
  535.      Last issue I explained  how to implement  a client for Drag&Drop  with
  536. File Manager. This was easy because it is well documented by Microsoft. But
  537. now, what if we  want to be the server  for Drag&Drop (e.g. if you  want to
  538. program your own file manager)?
  539.  
  540.      There  is no documentation from  Microsoft for this,  so the following
  541. can change with the next version of Windows.
  542.  
  543.      The first we have to do is capturing the mouse. This is done by
  544.  
  545.   SetCapture(HWindow);
  546.  
  547. where HWindow is  the handle of  the window that  should receive the  mouse
  548. messages. Now we will receive WM_MouseMove messages every time the mouse is
  549. moved even if the mouse is not in your client window.
  550.  
  551.      If the mouse was  moved, we have to detect if the  window at the point
  552. of the cursor is registered to accept dropped files.
  553.  
  554. So we have to process WM_MOUSEMOVE messages:
  555.   1) You can get  the current position of the  cursor when the message  was
  556. sent by:
  557.  
  558.        Point.X := LoWord(GetMessagePos);
  559.        Point.Y := HiWord(GetMessagePos);
  560.  
  561.   2) Now we can get the window at this Point:
  562.  
  563.        DragWnd := WindowFromPoint(Point);
  564.  
  565.   3) To check if the DragWnd is registered to accept dropped  files we have
  566. to check if  the window has the exStyle ws_Ex_AcceptFiles.  If the Style is
  567. set, we  will set the cursor  to a cross, if  not we will  set the standard
  568. cursor: 
  569.  
  570.        if GetWindowLong(DragWnd,gwl_ExStyle) and ws_Ex_AcceptFiles =
  571.                   ws_Ex_AcceptFiles then
  572.          SetCursor(LoadCursor(0,idc_Cross))
  573.        else
  574.          SetCursor(LoadCursor(0,idc_Arrow));
  575.  
  576.      ws_Ex_AcceptFiles has a value of $00000010;
  577.  
  578.  
  579.      Now if the mouse button is released we have to release the capture and
  580. set the default cursor with
  581.  
  582.   ReleaseCapture;
  583.   SetCursor(LoadCursor(0,idc_Arrow));
  584.  
  585.      Get the DropWnd under the  cursor (see above) and if the  window under
  586. the  mouse is  a D&D  window  (see above)  we have  to post  a wm_DropFiles
  587. message to it. But in this message we have to set wParam to a handle with a
  588. Drag&Drop structure and the format of this structure is not documented.
  589.  
  590. I found out that the structure looks like this:
  591.  
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.   type PDragDropStruct =^TDragDropStruct;
  599.        TDragDropStruct = record
  600.          DataOffset      : word;
  601.          DropPoint       : TPoint;
  602.          DropInNonClient : bool;
  603.          Data            : array[0..0] of char;
  604.        end;
  605.  
  606. The meanings of the parts of this structure are:
  607.   1) DataOffset :
  608.        This is the offset where the filenames begin.
  609.   2) DropPoint
  610.        This is the point where the mouse was released.
  611.        The coordinates are client coordinates.
  612.   3) DropInNonClient
  613.        This flag is set if the mouse was released in the non-client area
  614.        of the window (e.g., title bar).
  615.   4) Data
  616.        Here is the beginning of the data. All filenames are separated by a
  617.        chr(0) and the end of this list is terminated by another chr(0).
  618.  
  619. Now we have to do the following:
  620. 1) Allocate memory for the Drag&Drop structure
  621. 2) Lock the memory
  622. 3) Set the data
  623. 4) Unlock the memory
  624. 5) Use the Handle to the memory as wParam
  625.  
  626. For example we want to have 3 files in the Drag&Drop structure
  627.  
  628. const s : array[1..3,0..255] of char=('C:\autoexec.bat',
  629.                                       'C:\config.sys',
  630.                                       'C:\dos\command.com');
  631.  
  632. We have to compute the length of all the strings
  633.  
  634.   l := 0;
  635.   for i := 1 to 3 do
  636.     l := l+ StrLen(s[i]);
  637.  
  638. and have to allocate memory for the  whole structure. The memory must be of
  639. the type gmem_DDEShare.
  640.  
  641.   DataHandle := GlobalAlloc(gmem_DDEShare,sizeof(TDragDropStruct)+l);
  642.  
  643. To set the data we lock the memory
  644.  
  645.   DataPtr := GlobalLock(DataHandle);
  646.  
  647. and fill the fields of the structure:
  648.  
  649.   with PDragDropStruct(DataPtr)^ do begin
  650.     DataOffset:=Data-DataPtr;
  651.     DropInNonClient:=(
  652.       DefWindowProc(DropWnd,wm_NCHitTest,0,longint(Point))<>htClient);
  653.     ScreenToClient(DropWnd,Point);
  654.     DropPoint   :=Point;
  655.   end;
  656.  
  657. where
  658.  
  659.  
  660.  
  661.  
  662.  
  663.  
  664.   DefWindowProc(DropWnd,wm_NCHitTest,0,longint(Point))<>htClient
  665.  
  666. will test if the cursor is not in the client area of the window.
  667.  
  668. The last data  we have to set are the filenames.  We do this with a pointer
  669. p. Initially we set p to the field data of the structure.
  670.  
  671.   p:=PDragDropStruct(DataPtr)^.Data;
  672.  
  673. Now  we copy each string to  p and set p at the  end of the string plus one
  674. (StrLen will not compute the chr(0)).
  675.  
  676.   for i:=1 to 3 do begin
  677.     StrCopy(p,s[i]);
  678.     p:=p+StrLen(s[i])+1;
  679.   end;
  680.  
  681. If we have copied all strings we have to terminate the list with a chr(0)
  682.  
  683.       p^:=#0;
  684.  
  685. At the end we have to unlock the memory with
  686.  
  687.   GlobalUnlock(DataHandle);
  688.  
  689. and post the wm_DropFiles message to the DropWnd:
  690.  
  691.   PostMessage(DropWnd,wm_DropFiles,DataHandle,0);
  692.  
  693.  
  694. The file D&DSER.PAS is a simple Drag&Drop server. Just press the left mouse
  695. button in the  client area and move it to the  window of a Drag&Drop client
  696. (e.g D&DCLI,  see below) and release the button. While moving the mouse the
  697. cursor  will  change to  a  cross, if  the  window under  the  cursor  is a
  698. Drag&Drop client.
  699.  
  700. D&DCLI.PAS is an implementation of a simple Drag&Drop client. It
  701. will print out the dropped files in a WinCrt window. It is nearly
  702. the same code as the trash can in the last issue.
  703.  
  704.  
  705.  
  706.  
  707.  
  708.  
  709.  
  710.  
  711.  
  712.  
  713.  
  714.  
  715.  
  716.  
  717.  
  718.  
  719.  
  720.  
  721.  
  722.  
  723.  
  724.  
  725.  
  726.  
  727.  
  728.  
  729.  
  730.                            C++ Beginner's Column
  731.                               By Mike Wallace
  732.  
  733.      I promised in the last issue I would start a beginner's column on C++,
  734. and I didn't want to lie to you.   I have been reading some books lately on
  735. C++ because I don't  know anything about it.  My plan is to learn enough to
  736. write a "Hello world" program in  C++ for Windows (for starters), gradually
  737. move on  to more advanced programs and  try to share with  you everything I
  738. learn along the way.  Hope this suits  you because it's the best way I  can
  739. think of to approach  this.  If you have  any suggestions/complaints please
  740. don't hesitate to  let me know.  We  have a ways to go before  we can start
  741. coding so be patient  for now.  This stuff can be a little bizarre, so I'll
  742. try to explain it as best I can.
  743.  
  744.      I've  been programming  for  about 10  years  and have  become  pretty
  745. comfortable with Pascal, C, COBOL, FORTRAN, BASIC and the rest  of the most
  746. popular languages, and I've noticed they have a lot of similarities when it
  747. comes to program structure, data abstraction, etc.  If you already know how
  748. to program and now want to learn C++, forget everything you've learned.  If
  749. you've never programmed before, then you're a step ahead of the rest of us.
  750. C++  is  unlike  anything  I've  seen  -  it's  a  whole  new  approach  to
  751. programming.  The best book I've seen on the subject is Borland's excellent
  752. "Object-Oriented Programming Guide"  that came  with Turbo Pascal  5.5.   I
  753. hope this guide  is still packaged with the latest version  of TP - chapter
  754. one is a great read and helped clear up some of the more mystifying aspects
  755. of OOP for me.
  756.  
  757.      OOP is something  like the sound of  one hand clapping -  if you don't
  758. think about  it too  hard and ignore  what you  already know, it's  easy to
  759. imagine.   Consider an apple.  In  abstract terms, it's just an object, and
  760. like  any object, it is described by  its physical properties (an apple has
  761. to have  weight, for example).   Think of these properties  as functions of
  762. the object.  It is important to keep in mind that we're not talking about a
  763. specific apple, but any apple that  ever existed.  The function describing,
  764. say, the weight, stays the same  - only the values going into the  function
  765. differ.   So,  the nature  of an  apple is  intertwined with  the functions
  766. describing it - they  can be encapsulated  to form an object.   This is  an
  767. important concept in  OOP.   "Encapsulation" refers to  combining a  record
  768. with the code that manipulates it to form an object.
  769.  
  770.      Let's move on  to an  example closer related  to programming:  drawing
  771. graphics.   If we wanted  to write  a program for  drawing lines,  circles,
  772. etc., we could  start with defining  an object called  Point, which has  as
  773. three fields:  x coordinate (integer),  y coordinate  (integer) and  on/off
  774. (boolean).  The first  two fields give the location of Point  and the third
  775. says if it  is displayed (on)  or not (off).   If we  wanted to extend  our
  776. program to  include circles, we could  a define a new  object called Circle
  777. that  had the same  fields as Point  plus a field  for the radius  (x and y
  778. would be the center of the circle).  To save time,  we could declare Circle
  779. as an object of type Point with another field for the radius.  Circle  is a
  780. descendent of Point  because Circle  has inherited the properties of Point.
  781. This  is  another concept  important to  understanding OOP.   "Inheritance"
  782. refers  to  defining  an object  and  using  it  as  a basis  for  defining
  783. descendent objects,  with  each descendent  inheriting  access to  all  its
  784. ancestors' code and data.
  785.  
  786.      Finally, let's say you want to write a routine for drawing a Point and
  787. another  for a  Circle.   Although  the two  routines would  be implemented
  788. differently, they're both doing  nothing more than  showing an object.   In
  789. C++, it is possible to declare two routines with the same name, and here we
  790.  
  791.  
  792.  
  793.  
  794.  
  795.  
  796. could do it with  the routine "Show."   The difference  between the two  is
  797. that one would  be tied to the object Point and  the other would be tied to
  798. Circle.   This is called  "polymorphism", and  is giving  an action  (here,
  799. showing  an arbitrary object) a single name  (e.g., "Show") that is used by
  800. different  objects in  the hierarchy  , with  each object  implementing the
  801. action in a manner suited to that object.
  802.  
  803.      Well, that's  all for  this month.   I've stayed  away from  code here
  804. because it's  too early to start with it.   C++ is too different than, say,
  805. C, to jump into code,  I think [that's his  way of saying he hasn't  gotten
  806. that  far either  - Pete].   I hope  this makes  sense so  far.   If you're
  807. thinking, "I never did this  with Pascal", then you're starting to  get the
  808. point.  It's not just a computer  language - it's a way of programming that
  809. reflects  the way we think, much more so  than C, for example.  Don't think
  810. too  hard about it and it should make more sense than what you already know
  811. about  programming.  If none  of this makes sense, drop  me a line and I'll
  812. see what I can do.
  813.  
  814.  
  815.  
  816.  
  817.  
  818.  
  819.  
  820.  
  821.  
  822.  
  823.  
  824.  
  825.  
  826.  
  827.  
  828.  
  829.  
  830.  
  831.  
  832.  
  833.  
  834.  
  835.  
  836.  
  837.  
  838.  
  839.  
  840.  
  841.  
  842.  
  843.  
  844.  
  845.  
  846.  
  847.  
  848.  
  849.  
  850.  
  851.  
  852.  
  853.  
  854.  
  855.  
  856.  
  857.  
  858.  
  859.  
  860.  
  861.  
  862.                              Beginner's Column
  863.                        By Mike Wallace and Pete Davis
  864.  
  865.      Last month  we  covered the  .DEF  file and  started  on resources  by
  866. describing  dialog boxes.    This  month  we'll  finish  the  .RC  file  by
  867. explaining  menus,  and then  begin on  the C  code  for our  "Hello World"
  868. program.
  869.      A Windows  program  isn't a  Windows  program without  a menu.    It's
  870. probably the  first thing you look  for when you're running  a Windows app.
  871. If you've wondered  how to create  one yourself, you've  come to the  right
  872. place.  You describe your menu in the .RC file using the following format:
  873.  
  874. <menu-name>    MENU
  875. BEGIN
  876.        POPUP "<popup menu>",
  877.        BEGIN
  878.                 MENUITEM "<menu item 1>",  <variable>[, options]
  879.         END
  880.         MENUITEM "<menu bar item>",  <variable>[, options]
  881. END
  882.  
  883.      You can have as many  menu items as you want (or will fit  on the menu
  884. bar),  and even have popup  menus inside other popup menus  if you want.  I
  885. kept  the  format  simple so  it  wouldn't  be  overwhelming.   Here's  the
  886. explanation for the codes:  anything inside "<>" is required,  and anything
  887. inside "[]" is optional.   You have to give your menu a  name.  You can put
  888. the  POPUPs  and MENUITEMs  in any  order you  want,  but don't  forget the
  889. BEGIN/END statements that go right after the POPUP statement.  Any MENUITEM
  890. inside the BEGIN/END appears under that  popup menu.  MENUITEMs that appear
  891. outside  the BEGIN/END of  a popup menu  appear on  the menu bar,  but they
  892. won't have a  menu under them.   For each menu item,  you should give it  a
  893. variable  (defined in a .H  file included in the .RC  file) that you'll use
  894. when your program checks for which menu item was selected by the user.  For
  895. any menu item, you can include the following options:
  896.  
  897. CHECKED   - The menu item has a check next to it
  898.  
  899. GRAYED    - The menu item text is grayed and inactive
  900.  
  901. HELP      - The item has a vertical line to the left.  You can also include
  902. a "\a" at
  903.              the beginning of the text if you want to item to appear on the
  904. menu 
  905.              bar's far right side.
  906.  
  907. INACTIVE  - The menu item name is displayed but cannot be activated.
  908.  
  909. MENUBARBREAK   - When used on a menu, the item is placed on a new line.  On
  910.              popups, the item is placed in a new column.   A line separates
  911. this 
  912.              item from the previous one.
  913.  
  914. MENUBREAK - Same as MENUBARBREAK, except for popup menus : no dividing 
  915.             line.
  916.  
  917.  
  918. A couple of more hints: If you want to make a character in a menu item name
  919. underscored (to allow for ALT-whatever), add an "&" before the character in
  920. the  name.   Also, you  can  add the  line  "MENUITEM SEPARATOR"  to add  a
  921. horizontal line between popup menu bar items.
  922.  
  923.  
  924.  
  925.  
  926.  
  927.  
  928.      We're now ready to write the .RC file for "Hello World".  Here it is:
  929.  
  930. /* hello.rc */
  931. #include <windows.h>
  932. #include <hello.h>
  933. amenu          MENU
  934. BEGIN
  935.           POPUP "&Text"
  936.           BEGIN
  937.                  MENUITEM "&Write",             IDM_WRITE
  938.           END
  939.           MENUITEM "&Quit",                      IDM_QUIT
  940.           MENUITEM "\a&Help",                  IDM_HELP, INACTIVE
  941. END
  942.  
  943.  
  944. Here's "hello.h":
  945. /* hello.h */
  946. /* define menu bar items */
  947. #define  IDM_WRITE   1
  948. #define  IDM_QUIT       5
  949. #define  IDM_HELP     10
  950.  
  951. /* function prototypes */
  952. Long FAR PASCAL MainWndProc (HWND, unsigned, WORD, LONG);
  953.  
  954.  
  955. The "windows.h" file  is included  with the Microsoft  Windows SDK, and  is
  956. required for  any Windows program.  The above two  files will change as our
  957. program grows, but it  should suit our needs  for now.  We'll describe  any
  958. changes we make to any file we've already created.  Here's Pete to tell you
  959. about the C code.
  960.  
  961.      Ok, so I  guess it's my turn  to talk about the coding  of this thing.
  962. This is a real bread and water Windows program, but it's got all the basics
  963. that you're going to find in all Windows programs, and that's what you need
  964. at this point.
  965.  
  966.      In a normal C program you have your main() function which is the first
  967. function to get called in  a C program. In Windows, instead of  main(), you
  968. have WinMain(). (Real original, eh?) The WinMain function is where you take
  969. care of all the initialization. The main things you want to do  is register
  970. your window class. Now, this makes it sound like object  oriented stuff all
  971. of  a sudden, and I  suppose it is, but all  you're really doing is telling
  972. Windows  a few things  about your  window. (You have  to keep  in mind that
  973. Windows is essentially  an object oriented  operating system. Although  our
  974. programming  isn't  object oriented,  per se,  we  are emulating  an object
  975. oriented programming environment.)
  976.  
  977.      Instead  of showing the Window Class structure here, I'll just discuss
  978. it. I've labeled  the members of the  structure in the  code, so you'll  be
  979. able to relate what I write here to the structure members in the code.
  980.  
  981.      The  hCursor is basically done by a load cursor. Most applications jut
  982. choose the generic IDC_ARROW cursor. 
  983.  
  984.      The hIcon is where you  really get to have fun. This is  the icon that
  985. is shown when your application is minimized.
  986.  
  987.      The hInstance is simply the instance for this application.
  988.  
  989.  
  990.  
  991.  
  992.  
  993.  
  994.      The  hbrBackground  is the  class  of the  background  brush, meaning,
  995. basically, the color or pattern used in your window. This is usually white.
  996.  
  997.      lpszMenuName  is a pointer to  a null-terminated string  which has the
  998. resource name of your menu.
  999.  
  1000.      style has several  options, most of  which are a  little more than  we
  1001. need  to  go  into  at  this  point. My  suggestion  is  use  CD_HREDRAW  |
  1002. CS_VREDRAW. This basically means to redraw the window if the  horizontal or
  1003. vertical window sizes change.
  1004.  
  1005.      The cbClsExtra and cbWndExtra are a bit more complex than we should be
  1006. going into at this point, so like so many other things, we'll hold them off
  1007. for another day. Just keep them NULL for now.
  1008.  
  1009.      After  registering  your  window class,  you  have  to initialize  the
  1010. instance. What  this means is that  in a Windows  program, you can  run the
  1011. same program several times at once  (not all Windows applications, but ones
  1012. that are written to  allow it.) Each copy of the program  running is called
  1013. an instance. The  reason you have  to initialize the  instance is  because,
  1014. each one  of those versions is going  to share the same  copy of code. (You
  1015. don't  have to share the code,  but it's bad practice not  to, so we're not
  1016. going to  say any more about  that no no.) Also,  because handling multiple
  1017. instances  of an application  can be a  bit tricky for  the beginner, we're
  1018. going to set up our code to reject attempts to run multiple instances.
  1019.  
  1020.      At the  end of  all of  this you set  up your  message queue.  This is
  1021. fairly simple to do and fairly generic. Most programs do this the same way.
  1022. There are  reasons for changing it,  sometimes, but we're not  going to get
  1023. into that either, at this point.
  1024.  
  1025.      When  you  initialize the  instance, you  also  tell Windows  what the
  1026. procedure  is that is  going to handle  the messages for  your main Window.
  1027. Here's  where the multi-tasking of  Windows takes place.  See, what Windows
  1028. does here is  that every  time something  happens in  your window,  Windows
  1029. calls this procedure and  passes along a message describing  what happened.
  1030. This  could be something  like a mouse  movement, a menu  selection, etc...
  1031. See, you never explicitly call the procedure that handles your main window,
  1032. what you do is tell Windows where the procedure is and it will know when to
  1033. call it.
  1034.  
  1035.      The  best  way to  handle your  main window  procedure  is to  setup a
  1036. switch/case  structure where each case  of your switch  statement handles a
  1037. different message.
  1038.  
  1039. example:
  1040.      /* Switch structure for message */
  1041.      switch(message) {
  1042.  
  1043.           case WM_CREATE:
  1044.                ....
  1045.                ....
  1046.                ....
  1047.                break;
  1048.  
  1049.           case WM_Another_Message:
  1050.                ....
  1051.                ....
  1052.                ....
  1053.                break;
  1054.  
  1055.  
  1056.  
  1057.  
  1058.  
  1059.  
  1060.           etc...
  1061.  
  1062.  
  1063.      Windows messages  generally start  with  WM_. The  WM meaning  Windows
  1064. Message, oddly enough. After each case would be the code to handle whatever
  1065. that  action requires. For example,  the WM_CREATE message  is called right
  1066. before a window (or dialog box for that matter) is created,  so it's a good
  1067. candidate for initializing variables and  that kind of stuff that you  want
  1068. to do every time your window is created.
  1069.  
  1070.      A little  side note here: There  are two types of  dialog boxes, Modal
  1071. and Modeless (Yes, one is al and  the other is el). The Modal dialog  boxes
  1072. are very similar to windows in that they are given a procedure that handles
  1073. messages that  are passed to them.  (We'll discuss Modal dialog  boxes at a
  1074. later time also. One thing at a time.)
  1075.  
  1076.      I digress... Anyway,  the break  after each case  statement is just  a
  1077. quick way out of the switch/case  structure. It basically means that you're
  1078. done handling that particular message.
  1079.  
  1080.      Ok, so what are we learning here? Well, Windows programs aren't linear
  1081. in the sense that you run  a procedure which may run another procedure  and
  1082. so on. Windows is  event driven which means  that it reacts to  events that
  1083. take  place. When you  move the mouse,  that's an event,  so your procedure
  1084. gets called. When  you hit a  mouse button, that's  another event, but  the
  1085. same  procedure  gets called.  This  procedure  should respond  differently
  1086. depending on the message it receives.
  1087.  
  1088.      That should  be all you need.  I've included the Hello  World code and
  1089. I've  put as much  inline documentation as  will make sense.  I suggest you
  1090. give it a whirl, and like  any of our articles, if you have  questions, let
  1091. us  know. If we've inadvertently  skipped something, send  us a message and
  1092. we'll amend our goofs.
  1093.  
  1094.      Next  month  you'll have  Dave Campbell  coming  to you  directly from
  1095. Arizona.  He's a hell of a  programmer, so he'll have lots  to show you and
  1096. hopefully, give you a  little different perspective  than Mike and I,  that
  1097. way if you don't understand  what we're saying, maybe you'll  understand it
  1098. when  Dave says it. So, so  long and thanks for  reading. Hope you'll treat
  1099. Dave as well as you've treated us.
  1100.  
  1101.  
  1102.  
  1103.  
  1104.  
  1105.  
  1106.  
  1107.  
  1108.  
  1109.  
  1110.  
  1111.  
  1112.  
  1113.  
  1114.  
  1115.  
  1116.  
  1117.  
  1118.  
  1119.  
  1120.  
  1121.  
  1122.  
  1123.  
  1124.  
  1125.  
  1126.                            Using LZExpand Library
  1127.                                 Alex Fedorov
  1128.  
  1129.      LZEXPAND.DLL is  supplied with Windows to allow  programmers to unpack
  1130. files,  previously packed with COMPRESS.EXE  utility. Here we  will look at
  1131. the  main functions  of this  library. Note,  that you  can  use EXPAND.EXE
  1132. utility to unpack files  instead of using functions from  LZEXPAND library.
  1133. Mostly,  this library is used  for installation programs.  (This article is
  1134. intended for TPW programmers).
  1135.  
  1136.  
  1137.      Data compression
  1138.  
  1139.      Data compression  is a task to  lower the file size  by converting the
  1140. repeated data with  some other sequences. In text  files such repeated data
  1141. can  be  spaces, mostly  used  chars or  even  the whole  strings.  Due the
  1142. compression  such repeated  sequences  are replaced  with the  shorter one.
  1143. Several data compression  algorithms exist. One of the most  popular is the
  1144. Huffman algorithm, based on  the frequencies of chars repetitions  in text.
  1145. Another  one is a run-length  encoding algorithm, where  the repeated chars
  1146. are replaced by pairs:  the first nibble contains the  count of repetitions
  1147. and the second one the char code itself. Also, the  Lempel-Ziv algorithm is
  1148. widely used and the COMPRESS.EXE utility is based on it.
  1149.  
  1150.  
  1151.      Data expansion
  1152.  
  1153.      Applications  use  functions   from  LZEXPAND.DLL  to   unpack  files,
  1154. compressed  with COMPRESS.EXE utility. Here  is the actions  flow to expand
  1155. one or more files.
  1156.  
  1157.      Unpacking one file:
  1158.  
  1159.           ~ Open a compressed file with LZOpenFile. Also,
  1160.           the file can be opened with OpenFile or LZInit
  1161.           functions.
  1162.  
  1163.           ~ Open a destination file using LZOpenFile or
  1164.           OpenFile functions.
  1165.           
  1166.           ~  Use LZCopy to copy data from source to
  1167.           destination using file handles from LZOpenFile
  1168.           or LZInit.
  1169.  
  1170.           ~ Close both files with LZClose.
  1171.  
  1172.  
  1173.      Unpacking several files:
  1174.  
  1175.      To unpack several files you perform the following actions:
  1176.  
  1177.           ~ Open source file with LZOpenFile or with
  1178.           OpenFile and LZInit functions.
  1179.  
  1180.           ~ Open destination file using LZOpenFile or
  1181.           OpenFile functions.
  1182.           
  1183.           ~ Allocate memory for copy operations with
  1184.           LZStart function.
  1185.  
  1186.  
  1187.  
  1188.  
  1189.  
  1190.  
  1191.  
  1192.           ~ Use CopyLZFile to copy source file to destination
  1193.           file.
  1194.  
  1195.           ~ Free allocated memory with LZDone function.
  1196.  
  1197.           ~ Close all files with LZClose function.
  1198.  
  1199.  
  1200.      Reading data from compressed files
  1201.  
  1202.      Instead  of unpacking the whole  file, an application  can unpack file
  1203. piece-by-piece, using LZSeek and LZRead  functions. These functions can  be
  1204. useful when we unpack the huge files.
  1205.  
  1206.      To  use the functions from LZEXPAND.DLL you need the unit LZEXPAND.TPU
  1207. which is supplied with Turbo Pascal for Windows 1.5 or  with Borland Pascal
  1208. for Windows.
  1209.  
  1210.      Here is the example of how to use LZEXPAND.DLL functions
  1211.  
  1212.      {       LZDEMO - The demo of LZEXPAND.DLL functions usage    }
  1213.  
  1214.      uses LZExpand,WinTypes,WinProcs;
  1215.  
  1216.      Const
  1217.       szSrc      = 'MYFILE.PAK';  {Packed file name}
  1218.      Var
  1219.       szFileName : Array[0..127] of Char;
  1220.       ofStrSrc   : TOfStruct;
  1221.       ofStrDest  : TOfStruct;
  1222.       hSrcFile   : THandle;
  1223.       hDstFile   : THandle;
  1224.       Total      : LongInt;
  1225.  
  1226.      Begin
  1227.      {Open compressed file}
  1228.       hSrcFile := LZOpenFile(szSrc,OfStrSrc,of_Read);
  1229.  
  1230.      {Get the original name of file}
  1231.       GetExpandedName(szSrc,szFileName);
  1232.  
  1233.      {Create the file with szFileName}
  1234.       hDstFile := LZOpenFile(szFileName,ofStrDest,of_Create);
  1235.      
  1236.      {Unpack file while copying it}
  1237.       Total := LZCopy(hSrcFile,hDstFile);
  1238.      {LZCopy returns the number of bytes written}
  1239.      
  1240.      {Close both files}
  1241.       LZClose(hSrcFile);
  1242.       LZClose(hDstFile);
  1243.      
  1244.      End.
  1245.      
  1246.      Note: In the  example above,  we used the  LZOpenFile function,  which
  1247. automatically  calls LZInit  function, which performs  some initialization.
  1248. The  result code of this function  can tell us whether or  not the file was
  1249. compressed with  COMPRESS.EXE. To do this,  you need to open  the file with
  1250. the OpenFile function (from  KERNEL) and then call LZInit  directly, giving
  1251. it the  file handle from OpenFile.  LZInit returns the file  handle. If the
  1252.  
  1253.  
  1254.  
  1255.  
  1256.  
  1257.  
  1258. value  for this  handle  is not  the same  as  the argument,  the file  was
  1259. compressed and we can unpack it. Here is the example:
  1260.  
  1261.           hSrcFile  := OpenFile(szSrc,ofStrSrc,of_Read);
  1262.           hCompFile := LZInit(hSrcFile);
  1263.           If hCompFile <> hSrcFile then
  1264.           
  1265.            {File was compressed with COMPRESS.EXE}
  1266.           
  1267.           Else If hCompFile = hSrcFile then
  1268.           
  1269.            {File was not compressed}
  1270.           
  1271.           Else
  1272.           
  1273.            {Some error encountered; must check LZError_XXX codes}
  1274.      
  1275.  
  1276.      Also note, the GetExpandedName function returns the original name only
  1277. when the file was compressed by COMPRES.EXE with /r option.
  1278.  
  1279.  
  1280.                                         Alex is a freelance programmer
  1281.                                    and the editor for "Computer Press"
  1282.                                    magazine. Alex lives in Moscow, Russia.
  1283.  
  1284.  
  1285.  
  1286.  
  1287.  
  1288.  
  1289.  
  1290.  
  1291.  
  1292.  
  1293.  
  1294.  
  1295.  
  1296.  
  1297.  
  1298.  
  1299.  
  1300.  
  1301.  
  1302.  
  1303.  
  1304.  
  1305.  
  1306.  
  1307.  
  1308.  
  1309.  
  1310.  
  1311.  
  1312.  
  1313.  
  1314.  
  1315.  
  1316.  
  1317.  
  1318.  
  1319.  
  1320.  
  1321.  
  1322.  
  1323.  
  1324.                    Implementing A Linked List - Revisited
  1325.                               By Mike Wallace
  1326.  
  1327.      I didn't expect this to happen.  I have caused a small uproar  by last
  1328. month's  article "Implementing  a  Linked  List  Using  the  Global  Heap."
  1329. Several people had differing  opinions on the best way to do  this, and two
  1330. of them have promised articles showing two different ways to do this, which
  1331. we hope to  publish soon.   Part  of it was  my fault:  at the  end of  the
  1332. article, I intended to mention that  it was very easy to alter the  program
  1333. to use the local heap (instead of the global heap) - all you need to do  is
  1334. change the  Global commands  (e.g., GlobalAlloc)  to Local  commands (e.g.,
  1335. LocalAlloc) and the FAR pointers  to NEAR.  I arbitrarily chose  the global
  1336. heap for the program, and several people pointed out (and for good reasons)
  1337. that it's always  better to use the local heap if  at all possible.  Hope I
  1338. haven't confused anybody.  In case anyone is interested in using the method
  1339. I  proposed last  month, then  I have  bad news:  there was  a bug  in last
  1340. month's  code  involving freeing  the memory  blocks.   I  have  included a
  1341. revised version of the program with this issue.
  1342.  
  1343.  
  1344.  
  1345.  
  1346.  
  1347.  
  1348.  
  1349.  
  1350.  
  1351.  
  1352.  
  1353.  
  1354.  
  1355.  
  1356.  
  1357.  
  1358.  
  1359.  
  1360.  
  1361.  
  1362.  
  1363.  
  1364.  
  1365.  
  1366.  
  1367.  
  1368.  
  1369.  
  1370.  
  1371.  
  1372.  
  1373.  
  1374.  
  1375.  
  1376.  
  1377.  
  1378.  
  1379.  
  1380.  
  1381.  
  1382.  
  1383.  
  1384.  
  1385.  
  1386.  
  1387.  
  1388.  
  1389.  
  1390.            An Introductory Look at DLLs and The Use of Make Files
  1391.                                By Rod Haxton
  1392.  
  1393.      Whenever  one begins learning Windows he/she always seems to hear talk
  1394. about  DLLs (Dynamic  Link  Libraries). Learning  Windows  is a  very  long
  1395. process. Like anything in  the programming world there's lots to learn, and
  1396. not that much time to learn it in. Thus, many beginning Windows programmers
  1397. bypass Petzold's chapter  on DLLs until a later time.  This article may not
  1398. be of great help in understanding DLLs for Windows programmers just getting
  1399. their feet wet.  But, if you  have been writing code  for Windows and  feel
  1400. competent, and have  not yet tackled DLLs, this code may  give you a little
  1401. understanding of  how DLLs work.  Also, if  you have some  understanding of
  1402. 80x86 assembly  language underneath-the-hood workings, this  will be useful
  1403. in understanding  how DLLs work in Windows. A bonus to this article is that
  1404. it  demonstrates how a  large application or  for that matter  any size app
  1405. should be laid out. The programming example accompanying this article shows
  1406. how source  code should be broken  up into seperate modules.  The demo also
  1407. makes use of Make files and  shows how they can help speed  the development
  1408. of projects, and also demonstrates how to break code up  into multiple code
  1409. segments. So often in Windows books the programs demonstrated are  built as
  1410. one application with one code  and data segment. This isn't really  what we
  1411. as developers need.
  1412.  
  1413.      In learning  DLLs there are  a few areas  that one should  focus on to
  1414. gain 'THE KNOWLEDGE'; this conjures up images of some  monks sitting around
  1415. reading thick books. Cutting and pasting code samples from on-line articles
  1416. or  typing them  in  will get  you something  working  but, if  you do  not
  1417. understand what is really  going on in Windows you will  be held hostage to
  1418. some unknown  events and also  your own  imagination, or the  lack thereof.
  1419. Thus, there are some things to focus on when learning about DLLs. They are:
  1420.  
  1421.           * DS != SS
  1422.           * Windows & DLLs entry/exit code
  1423.           * Exports & Imports
  1424.           * LibEntry & LibMain
  1425.           * WEP function
  1426.  
  1427.  
  1428.                DS != SS
  1429.                --------
  1430.  
  1431.      In  a regular Windows application  program the Stack  and Data Segment
  1432. are the same. If  you set up your  program to have multiple code  segments,
  1433. the Code segments  can change during Windows function calls, far calls, and
  1434. return  from far  calls.  The changing  of the  code  segments takes  place
  1435. because most code segments are flagged as  moveable and discardable. If the
  1436. code segment has been flagged as a fixed segment then the code segment will
  1437. stay put. But,  in understanding DLLs you need to concentrate on DS and SS.
  1438. As I mentioned, in regular  Windows apps DS == SS. Standard  C routines can
  1439. be  used  in non-DLL  apps. They  do  not assume  DS ==  SS,  and generally
  1440. reference pointer variables  relative to  DS.  Remember, when functions are
  1441. called  a stack frame  is created,  which holds  the passed  variables, the
  1442. returning CS:IP  address, and space is created  to hold any local variables
  1443. to the routine. Thus,  references to your passed-in near  pointer variables
  1444. are seen by the stack, because C does not make a distinction  between stack
  1445. segment-based variables and data segment-based variables.
  1446.  
  1447.      DLLs on  the other hand have their own data  segments.  This is one of
  1448. the  reasons  that makes  them appealing  to  those developers  writing big
  1449. applications. When a routine to a DLL is called, the calling function's, if
  1450.  
  1451.  
  1452.  
  1453.  
  1454.  
  1455.  
  1456. its not in  the DLL, DS and CS  are placed on the stack.   The DLL uses the
  1457. stack of the calling  function. The DLL's DS and CS  are given scope. Thus,
  1458. the calling app (if passing any variables to the DLL) must pass them as far
  1459. pointers  in  order  for the  variables  to have  scope.  Also,  standard C
  1460. routines  cannot be  used,  because  DS !=  SS,  and the  standard  library
  1461. routines  reference the  variables from  DS. If  you do  call a  standard C
  1462. routine or another  DLL's function  with near pointers,  when the  function
  1463. returns  the variables will  be unchanged. Ways to  get around this problem
  1464. are to  declare your local variables in your DLL  as static or pass them as
  1465. far pointers.
  1466.  
  1467.  
  1468.           APP                                 DLL
  1469.      ---------------                    ---------------
  1470.      |             |                    |             |
  1471.      |     CS      |                    |      CS     |
  1472.      ---------------                    ---------------
  1473.            DS                                  DS
  1474.  
  1475.                       SHARED
  1476.       SS------------------------------------------------SS
  1477.  
  1478.  
  1479.      A detailed  discussion of DS !=  SS can be found  in Charles Petzold's
  1480. 'Programming Windows', and  Mike Klein's  'DLLs And  Memory Management'.  A
  1481. step to really comprehending DLLs is to understand DS != SS.
  1482.  
  1483.  
  1484.  
  1485.                Windows & DLLs Entry/Exit Code
  1486.                ------------------------------
  1487.  
  1488.      Another  aspect of  understanding DLLs  is to  understand how  Windows
  1489. loads application functions and DLLs. Again, here a little understanding of
  1490. how a MS-DOS C compiler handles function  loading and assembly language can
  1491. be helpful. Now,  if you  do not  happen to  be a  low-level system  person
  1492. and/or  have  no desire  to be,  you  may be  asking yourself  why  this is
  1493. important. Well, this really isn't important if you don't mind writing code
  1494. and not understanding what's really taking place. But remember, you will be
  1495. at a real disadvantage when a bug crops up and you go into your debugger to
  1496. find out what is wrong and you have no idea of what you're looking for. 
  1497.  
  1498.      Under DOS the compiler sets up segments as the following:
  1499.  
  1500.           mov  ax, _DATA
  1501.           mov  ds, ax
  1502.  
  1503. And, function entry/exit code saves registers and makes space on the  stack
  1504. for passed variables and local variables,
  1505.  
  1506.           push bp
  1507.           mov  bp, sp
  1508.           sub  sp, <number of bytes needed>
  1509.           .
  1510.           .
  1511.           .
  1512.           mov  sp, bp
  1513.           pop  bp
  1514.           ret       ;This  can   be  a  near   or  far  return.   Also,  if
  1515.                     ;the    function   was    called   with    the   PASCAL
  1516.  
  1517.  
  1518.  
  1519.  
  1520.  
  1521.  
  1522.                     ;directive    the    number   of    parameters   passed
  1523.                     ;to   the   stack   needs    to   be   added   to   the
  1524.                     ;return.
  1525.  
  1526.      Windows functions  are all set up  to be far calls.  This provides the
  1527. built-in ability  to swap and discard  code segments in and  out of memory.
  1528. The  entry exit  code for  the non-exported  far functions  looks like  the
  1529. following:
  1530.  
  1531.           push ds -----------------------| same as:
  1532.           pop  ax -----------------------|   mov ax, ds
  1533.           nop
  1534.           inc  bp
  1535.           push bp
  1536.           mov  bp, sp
  1537.           push ds               ----------------------   save   ds   again?
  1538.           mov  ds, ax ---------------------- here again ?
  1539.           sub  sp, <number of bytes>
  1540.           .
  1541.           .
  1542.           .
  1543.           dec  bp
  1544.           dec  bp
  1545.           mov  sp, bp
  1546.           pop  ds
  1547.           pop  bp
  1548.           dec  bp
  1549.           ret  <number of passed parameters>
  1550.  
  1551. Looking  at the  Windows entry/exit  code above  we see  that it  is really
  1552. similar to the DOS version.  It just does extra  work. The reason being  is
  1553. that Windows modifies the entry code when your exported function is called.
  1554. Windows replaces the first two instructions  ('push ds' and 'pop ax')  with
  1555. NOPs.  If you noticed the code above where I have stated 'here again?', the
  1556. instruction is 'mov  ds, ax'. But, now ax contains  nothing. Before it held
  1557. the value of ds. What  happens is that during LINK Windows  places into EXE
  1558. file a  table that  lists  the references  to your  far  calls and  Windows
  1559. functions. Thus, when Windows runs and calls your far function the register
  1560. ax has already been loaded with the segment location. Exported functions DS
  1561. are  handled during the registering  of window class  structures created or
  1562. with  the MakeProcInstance  for call-back  functions. The  MakeProcInstance
  1563. tells Windows to  do some 'thunking'.  Thunking handles the  setting up  of
  1564. code  and data segments. Each instance of  a Windows function will have its
  1565. own DS, but all instances will refer to one CS.
  1566.  
  1567. Far calls and Window functions entry code:
  1568.  
  1569.           nop
  1570.           nop
  1571.           nop
  1572.           inc  bp
  1573.           push bp
  1574.           mov  bp, sp
  1575.           push ds     
  1576.  
  1577.           mov  ds,    ax---------------->'Instance   Thunk'    located   in
  1578.                               fixed memory position.
  1579.                               mov  ax, <DS for instance>
  1580.  
  1581.           sub  sp, <number of bytes>
  1582.  
  1583.  
  1584.  
  1585.  
  1586.  
  1587.  
  1588.  
  1589.  
  1590.      DLLs entry code  is as simple as the  DOS version.  Because  DLLs have
  1591. their own DS and there can only be one instance of a DLL there's no need to
  1592. determine the DLL's DS at run time  or create an instance thunk. The DS  is
  1593. already known so it can be set.
  1594.  
  1595.           mov  ax, <DLL DS>
  1596.           inc  bp
  1597.           push bp
  1598.           mov  bp, sp
  1599.           push ds     
  1600.           mov  ds, ax
  1601.  
  1602.  
  1603.  
  1604.                Exports and Imports
  1605.                -------------------
  1606.  
  1607.      You should already know  about Exported functions if you  have written
  1608. Windows  code. But,  here's a  brief tutorial.  All Windows  functions that
  1609. receive  messages  must be  exported. The  export  tells the  compiler that
  1610. references to the exported functions will be resolved at run-time. 
  1611.  
  1612.      Imported functions are also  used to resolve function  references. The
  1613. IMPORTS statement  in a DEF  file tells the  Linker that the  functions are
  1614. defined elsewhere  and  relocation  info  will  be  resolved  at  run-time.
  1615. Imported functions can be handled in two ways. One is to list them in a DEF
  1616. file under  the IMPORTS statement. The other is to  place them in an import
  1617. library and link them into your code. The latter is the approach that I use
  1618. because it reduces the  headache of updating DEF files  during development.
  1619. Also, listing  the  import  functions  in  DEF  files  requires  a  lot  of
  1620. memorization when you  start dealing with multiple DLLs. Later, I will show
  1621. how I handle multiple DLLs and imports.
  1622.  
  1623.  
  1624.                LibEntry and LibMain
  1625.                --------------------
  1626.  
  1627.      Every Windows executable  modules needs an  entry point. When  writing
  1628. apps  for Windows this  code is  hidden from  the developer.  However, when
  1629. writing  DLLs the  source  to the  library  entry routine,  LibEntry(),  is
  1630. provided to you by the  SDK. Usually, you do not have to touch  this code -
  1631. the SDK  provides 'libentry' for you  to link into your  DLL. 'libentry' is
  1632. the object file for LibEntry(). If you are creating a resource-only DLL you
  1633. do have to modify LibEntry() a little bit. LibEntry() also calls a function
  1634. LibMain() that you must supply.
  1635.  
  1636.      When  the application program starts up all  DLLs tied to that app get
  1637. called. The initial  call for the DLL is the only  guaranteed time that the
  1638. library  will be  called. LibEntry()  initializes the  DLL's local  heap by
  1639. making a call to LocalInit(). Under Windows 3.0, due to  Real Mode support,
  1640. LocalInit() locks  the DLL's data segment; the  locking of the data segment
  1641. does not take place under Windows 3.1. On exit from LocalInit(), LibEntry()
  1642. calls LibMain(). If  the data  segment was locked  your LibMain()  function
  1643. must unlock it. 
  1644.  
  1645.      LibEntry() and LibMain() initialize your DLL and are only called once.
  1646. You will  see  in my  Make  and DEF  files  that I  place LibMain()  in  an
  1647. initialization code  segment. This way the segment will be flagged after it
  1648.  
  1649.  
  1650.  
  1651.  
  1652.  
  1653.  
  1654. is  used to be discarded and when memory becomes an issue it will be dumped
  1655. by Windows.
  1656.  
  1657.  
  1658.  
  1659.                WEP Function
  1660.                --------------
  1661.  
  1662.      The WEP() routine  is another function  that your DLL  is required  to
  1663. have. The SDK says that this function gets called once, when a DLL is about
  1664. to be unloaded. This does not seem to be the case under Windows 3.0. When I
  1665. have watched  it under Codeview, I have never  seen it called. WEP() has an
  1666. input parameter that  identifies whether the  exit is  being caused by  the
  1667. system or  the application. Whatever  the reason for the  exit WEP() should
  1668. return 1. You will notice in my examples  that I do not do any testing  for
  1669. the type of exit:  I just return  1. WEP()'s name is  made resident in  the
  1670. DLL's name table, thus it is always in memory and never gets swapped out.
  1671.  
  1672.  
  1673.                Programming Example
  1674.                -------------------
  1675.  
  1676.      Now that the  basics of DLLs have been discussed.  I'll focus the rest
  1677. of  this article on  a sample DLL  app that I've  written that demonstrates
  1678. DLLs,  the use  of Near/Far  function calls,  Near/Far pointers,  calling a
  1679. Dialog Box function located in a DLL, how to create  an import library, the
  1680. use of Make files, and how to create multiple code segments.
  1681.  
  1682.      The following  DLL example is  called RODSAPP (how  appropriate). It's
  1683. comprised of  an  application program  and  two  DLLs. The  app  files  are
  1684. rodsapp.c, winmain.c,  and wndproc.c. The file rodsapp.c  contains code for
  1685. creating and  initializing the  Windows application.    The file  winmain.c
  1686. handles the Windows message dispatcher.  The wndproc.c module is a standard
  1687. Windows function that  has a menu bar.  The menu bar is the  entry into the
  1688. DLLs. The menu items are About,  One and Two. Clicking on the About  option
  1689. demonstrates  a dialog box whose  function resides inside  a DLL (lib2a.c).
  1690. Clicking on menu option One causes a call to the testlib.dll (testlib.c).
  1691.  
  1692.      The function  StepOne inside  testlib.dll demonstrates  variables that
  1693. are referenced from DS and SS.  I've provided total explanations inside the
  1694. source so that understanding would be easier. 
  1695.  
  1696.      Clicking  on menu option Two also makes  a call to testlib.dll that in
  1697. turn calls the  DLL lib2.c. The calls  inside these DLLs  also demonstrates
  1698. what happens to variables that are referenced from DS and SS.
  1699.  
  1700.      The  Make  file  used with  the  program  compiles  with the  Codeview
  1701. debugger options set. I suggest  that you run the program under  Codeview a
  1702. few  times and  keep an eye  on the  DS and  SS registers. Also,  watch the
  1703. variables inside routines and  note their addresses and watch  what happens
  1704. to those variables addresses when you step into a routine inside a DLL.
  1705.  
  1706.      Along with the source files is  a batch program DOALL.BAT. It runs all
  1707. the Make files  and dumps any warning or error messages out to a file named
  1708. peek.
  1709.  
  1710.      Also, the Make file LIB.MAK creates an import library 'test.lib'. This
  1711. Make  file should be run  first in order to create  the import library that
  1712. will be linked into the DLLs. Changes to the DEF files will re-make LIB.MAK
  1713. but  the *.dll  files must  be deleted  and re-linked  with the  new import
  1714.  
  1715.  
  1716.  
  1717.  
  1718.  
  1719.  
  1720. library.
  1721.  
  1722.  
  1723.                Make File Explanation
  1724.                ---------------------
  1725.  
  1726.      The following is a snippet of the rodsapp.mak Make file; note that the
  1727. following statements that  begin with '*' do not appear  in the actual Make
  1728. file.
  1729.  
  1730. TMPDRIVE=c:\tmp
  1731.  
  1732. WLIB=libw mlibcew        *sets   up  a   macro  for   the  libraries   that
  1733.                          *will be used during linking
  1734.  
  1735. IMPLIBS=test             *the DLLs import library (see next  
  1736.                          *section    for    how     this    library     was
  1737.                          *created).
  1738.  
  1739.  
  1740. * object code of the modules used in RODSAPP.EXE
  1741. OBJ=rodsapp.obj winmain.obj wndproc.obj
  1742.  
  1743. * compiler option flags; a detailed meaning found in source
  1744. CFLAGS=cl /c /AM /D LINT_ARGS /Gws /W3 /Zip /Od /nologo
  1745.  
  1746. # Update the executable file if necessary, and if so, add the
  1747. # resource back in. The /NOE must be included when linking with 
  1748. # Windows libraries.
  1749.  
  1750. rodsapp.exe: $(OBJ) rodsapp.res rodsapp.def
  1751.         del $(TMPDRIVE)lk.res
  1752.         echo $(OBJ)>>$(TMPDRIVE)lk.res
  1753.         echo rodsapp.exe/align:16>>$(TMPDRIVE)lk.res
  1754.         echo rodsapp.map/map/NOD/CO/LI>>$(TMPDRIVE)lk.res
  1755.         echo $(WLIB) $(IMPLIBS)>>$(TMPDRIVE)lk.res
  1756.         echo rodsapp.def>>$(TMPDRIVE)lk.res
  1757.         link  @$(TMPDRIVE)lk.res
  1758.         rc rodsapp.res
  1759.  
  1760. # Update the object file if necessary
  1761.  
  1762. * The following demonstrates how to seperate your code into code
  1763. * segments. The -NT allows one to name the code segment. This 
  1764. * name is then placed in the modules DEF file under the SEGMENTS 
  1765. * statement and given the control flags that you wish the code 
  1766. * segment to follow.
  1767.  
  1768. rodsapp.obj: rodsapp.c rodsapp.h
  1769.         $(CC) $(CFLAGS) -NT Initialization_code rodsapp.c
  1770.  
  1771. winmain.obj: winmain.c rodsapp.h
  1772.         $(CC) $(CFLAGS)  -NT Resident_code winmain.c
  1773.  
  1774. wndproc.obj: wndproc.c rodsapp.h testlib.h
  1775.         $(CC) $(CFLAGS)  -NT Resident_code wndproc.c
  1776.  
  1777. # Update the resource if necessary
  1778. rodsapp.res: rodsapp.rc rodsapp.h
  1779.         rc -r rodsapp.rc
  1780.  
  1781.  
  1782.  
  1783.  
  1784.  
  1785.  
  1786.  
  1787.                DEF File Differences
  1788.                ---------------------
  1789.  
  1790.      The differences between a  Windows application definitions file and  a
  1791. DLL's is that  in the Windows app  DEF file there is a  NAME statement that
  1792. defines the app's name. A DLL has a LIBRARY statement to do the same thing.
  1793. A  DLL does  not need a  STUB statement  since it  cannot be  launched into
  1794. execution  without  an application  calling  it. A  DLL  also has  no STACK
  1795. statement. Since  the DLL uses the  SS of the calling  application it needs
  1796. not define a stack size.
  1797.  
  1798.  
  1799.                Conclusion
  1800.                -----------
  1801.  
  1802.      Things  to consider when developing applications  and using DLLs. DLLs
  1803. are not magical elements to be used for everything. If you can do something
  1804. fast and it's  only going to be used  by one application, that is  the code
  1805. will never really be used in some future app, stay away from DLLs. DLLs are
  1806. slow.  It takes numerous cycles  to load DLLs,  segment adjustments must be
  1807. made.  The DLL  far call  means that  the code  and  data segments  must be
  1808. loaded.
  1809.  
  1810.      Hopefully this article will help you in your understanding  of DLLs. I
  1811. hope that  the code samples  are clear enough to  help you. I  tried not to
  1812. give too  much code, which can be overwhelming when you are trying to learn
  1813. something, but just enough to represent the makeup of real projects.
  1814.  
  1815.      There  are other  topics under  DLLs that  I did  not cover  like User
  1816. Resource DLLs and  the handling of  global data across DLLs.  Maybe someone
  1817. else will provide an  article on User Resource DLLs in a  future article. I
  1818. plan to submit for the next issue of WPJ an article that demonstrates a way
  1819. I figured out to handle global variables across DLLs. Good luck! 
  1820.  
  1821.      Rod Haxton can be contacted @ (703) 883-0226 or (202) 269-3780.
  1822.  
  1823.  
  1824.  
  1825.  
  1826.  
  1827.  
  1828.  
  1829.  
  1830.  
  1831.  
  1832.  
  1833.  
  1834.  
  1835.  
  1836.  
  1837.  
  1838.  
  1839.  
  1840.  
  1841.  
  1842.  
  1843.  
  1844.  
  1845.  
  1846.  
  1847.  
  1848.  
  1849.  
  1850.  
  1851.  
  1852.                          The Windows Help Magician
  1853.                               By Jim Youngman
  1854.  
  1855.      Since I  do not  program  for the  sake of  programming,  I am  always
  1856. looking for shortcuts.  The Windows  Help Magician has proven to be  one of
  1857. the best.  I think it was written  in Visual Basic, but don't let that  put
  1858. you off it.   It's a great little application  and a real time saver.   The
  1859. files it produces can be compiled with Microsoft  or Borland Help Compilers
  1860. for Windows 3.0 or 3.1.
  1861.  
  1862.      I am writing my first fully fledged Windows program.  It is to be used
  1863. mainly  by  computer illiterate  people and  so a  good  Help file  will be
  1864. essential.
  1865.  
  1866.      When  I  started  investigating  how  to  prepare  such  files  I  was
  1867. overwhelmed by the prospect: all  those control characters that have  to be
  1868. inserted!  The Windows  Help Magician eliminates all of that.  Using a well
  1869. designed interface, the  program does all of the hard work.   All I need to
  1870. do is think out the design of the Help system.  The friendly Magician gives
  1871. me a  great set of tools  for creating the index,  browse groups, hypertext
  1872. jumps, popups  and keywords.   You can  also include bitmaps  in your  help
  1873. files.
  1874.  
  1875.      So far I have  only played about a bit with the product.  I am looking
  1876. forward to exploring it further with the real job.
  1877.  
  1878.  
  1879.      The Windows Help Magician is available from the publishers:
  1880.  
  1881.                Software Interphase Incorporated
  1882.                82 Cucumber Hill Road, Foster, RI 02825, USA
  1883.                FAX (401) 397-6814
  1884.                BBS (401) 397-4601
  1885.  
  1886.      There is a fully operational demo  disk which is limited to help files
  1887. of 7 pages.  The full version allows 200 pages.
  1888.  
  1889.  
  1890.  
  1891.  
  1892.  
  1893.  
  1894.  
  1895.  
  1896.  
  1897.  
  1898.  
  1899.  
  1900.  
  1901.  
  1902.  
  1903.  
  1904.  
  1905.  
  1906.  
  1907.  
  1908.  
  1909.  
  1910.  
  1911.  
  1912.  
  1913.  
  1914.  
  1915.  
  1916.  
  1917.  
  1918.                                The Last Page
  1919.                               By Mike Wallace
  1920.  
  1921.      This is too  cool.  Pete and I hoped a  couple of hundred people might
  1922. pick  up  the first  issue  of  WPJ (Official  motto:  "It's  not just  for
  1923. breakfast  anymore").   After three  weeks on  various bulletin  boards, we
  1924. counted over a thousand, and that doesn't even include Internet (we have no
  1925. way of  tracking the  number of  downloads there).   We've gotten  mail and
  1926. articles from such  faraway places  as Russia, Germany,  South America  and
  1927. central Jersey.  We hope the number of downloads goes up every month; if it
  1928. starts to go down, we're in trouble.  From the mail we've received,  people
  1929. seem to like it and want to help  out.  It's been overwhelming.  If  you're
  1930. thinking of writing  an article, don't be  shy.  Others are doing  it.  You
  1931. don't have  to be a professional writer (we sure aren't), and we can always
  1932. use more articles.  If you don't feel  up to writing an article, send us  a
  1933. message  and let us know  what you think about the  magazine.  Does it have
  1934. the putrid stench of rotting eggs?  Has it helped your Windows programming?
  1935. Inquiring minds want to know.   Remember: this is your magazine as  much as
  1936. our's.
  1937.  
  1938.      The only thing I'm disappointed about is I haven't gotten any mail for
  1939. this  column.  I really hope you people don't make me write this whole page
  1940. by myself!   As much  as I wish  I could fill  this page with  poetic prose
  1941. every month, that just ain't gonna happen.  What's  on your mind?  The only
  1942. programmers I know all  live in Washington, D.C. (Official  driving slogan:
  1943. "Death before yielding"), and here everyone is a government contractor, and
  1944. there's only so much you can talk about with a contractor before things get
  1945. really  dull.   What are  programmers doing  in, say,  California?   Texas?
  1946. Europe?  I know you people have something on your mind and you're thinking,
  1947. "If only  there  was some  sort of  internationally distributed  electronic
  1948. forum  for sharing  my most personal  thoughts with  people who  will write
  1949. about me  in their  local newspapers  and ban me  from ever  visiting their
  1950. country..."  Well, wonder  no more, because now you have  your chance.  You
  1951. can get  your 15 minutes of fame  simply by writing anything  (and I really
  1952. mean ANYTHING [He means within reason -Pete])  that both piques my interest
  1953. and,  most importantly, means I don't have to write as much.  What could be
  1954. simpler?
  1955.  
  1956.      While  I'm thinking about it, I want  to thank the hard-working sysops
  1957. on CompuServe,  and especially  in the  WINSDK forum.   I've  flooded these
  1958. people with questions lately and they've been great, and I really hope they
  1959. don't mind  if I  use their answers  in future  WPJ articles (ha!  ha! just
  1960. kidding!).  Seriously, these people really know their stuff and will answer
  1961. any question,  no matter how inane  (take it from someone  who's asked more
  1962. than  one inane  question).   An "Honorable  Mention" goes  to sysop  Tammy
  1963. Steele for  her wealth of  knowledge and great attitude.   Stop by  the WPJ
  1964. offices anytime to pick up your official WPJ t-shirt, Tammy.
  1965.  
  1966.      I'm out of room and out of time.  Hope to hear from ya'll soon.
  1967.  
  1968.  
  1969.  
  1970.  
  1971.  
  1972.  
  1973.  
  1974.  
  1975.  
  1976.  
  1977.  
  1978.  
  1979.  
  1980.  
  1981.  
  1982.  
  1983.  
  1984.                          Getting in touch with us:
  1985.  
  1986.      Right  now there are  only four ways to  get in touch  with us. If you
  1987. have access to the Internet or BITNET, you can get in touch with us at:
  1988.  
  1989. HJ647C at GWUVM.GWU.EDU -or- HJ647C at GWUVM.BITNET (Pete)
  1990.  
  1991. GEnie: P.DAVIS5 (Pete)
  1992.  
  1993. CompuServe: 71141,2071 (Mike)
  1994.  
  1995. WPJ BBS (703) 503-3021 (Mike and Pete)
  1996.  
  1997. You can also send paper mail to:
  1998.  
  1999. Windows Programmer's Journal
  2000. 9436 Mirror Pond Drive
  2001. Fairfax, VA   22032
  2002.       U.S.A.
  2003.  
  2004.      As soon as we replace the hard drive, the Windows Programmer's Journal
  2005. BBS  can be reached at:  (703) 503-3021. You  can get in  touch with either
  2006. Mike or Pete  at this  number. The BBS  is going to  be relatively new,  so
  2007. don't be surprised if it's a little buggy in the beginning. Right now  it's
  2008. only 2400 baud as my 9600 baud modem  died on me, soon you can expect it to
  2009. go up to 14,400. You can also expect to see a Fido-net node address  in the
  2010. near future..
  2011.  
  2012.      In  future issues  we will  be posting  addresses of  contributors and
  2013. columnists who don't mind you knowing their addresses. We will also contact
  2014. any  writers from the  first two  issues and  see if  they want  their mail
  2015. addresses made  available for you  to respond to  them. For now,  send your
  2016. comments to us and we'll forward them.
  2017.  
  2018.  
  2019.  
  2020.  
  2021.  
  2022.  
  2023.  
  2024.  
  2025.  
  2026.  
  2027.  
  2028.  
  2029.  
  2030.  
  2031.  
  2032.  
  2033.  
  2034.  
  2035.  
  2036.  
  2037.  
  2038.  
  2039.  
  2040.  
  2041.  
  2042.  
  2043.  
  2044.  
  2045.  
  2046.  
  2047.